clear;clc
%标准BP算法
x=[1.24,1.27;1.36,1.74;1.38,1.64;1.38,1.82;1.38,1.90; 
 1.40,1.70;1.48,1.82;1.54,1.82;1.56,2.08;1.14,1.82;1.18,1.96;1.20,1.86;1.26,2.00 
 1.28,2.00;1.30,1.96];
y=[1 0;1 0;1 0;1 0;1 0;1 0;1 0;1 0;1 0;0 1;0 1;0 1;0 1;0 1;0 1];  %初始数据

[v,r,w,h,y_hat]=standard_BP(x,y,1,1e6);

V=[-2 2 -2 2];
P=[0.1 0.7 0.8 0.8 1.0 0.3 0.0 -0.3 -0.5 -1.5;1.2 1.8 1.6 0.6 0.8 0.5 0.2 0.8 -1.5 -1.3];
T=[1 1 1 0 0 1 1 1 0 0;0 0 0 0 0 1 1 1 1 1];
%取一数组限制坐标值的大小
plotpv(P,T,V);
%该函数用于在感知器向量图中绘制其要分类的矢量图
axis('equal'),
%令横坐标和纵坐标单位距离相等
title('Input Vector Graph'),
%命名图的标题
xlabel('p1'),
%命名横轴坐标
ylabel('p2'),
%命名纵轴坐标
plotpc(w',h');
%该函数用于绘制感知器的输入矢量的目标向量，即在plotpv中把最终的分界线画出来

x_k=[1.24 1.80;1.28 1.84;1.40 2.04];

function [v,r,w,h,y_hat]=standard_BP(x0,y0,q,N)  %q为隐层单元数目,N,迭代次数

%初始化连边权值和阀值
L=size(y0,2);    %输出单元数目
[m,n]=size(x0);  %获取数据的维度
v=rand(n,q);  %初始化输入层到隐层的权值
r=rand(1,q);    %初始化隐层的阀值
w=rand(q,L);  %初始化隐层到输出层的权值
h=rand(1,L);    %初始化输出层的阀值
k=0.05;        %学习率
E=1;

iter=1;
a=1;

while iter<N
    x=x0(a,:);
    y=y0(a,:);
    
    A=x*v;                %输入层->隐层,各个隐层单元具有的权值
    b=fc_sigmod(A-r);     %经过隐层的激活函数的输出
    
    B=b*w;                %隐层->输出层,各个输出层单元具有的权值
    y_hat(a,:)=fc_sigmod(B-h); %经过输出层的激活函数的输出
    
    E=0.5*sum((y_hat(a,:)-y).^2);  %求均方误差
    
    %以下对各个系数进行调整
    g=y_hat(a,:).*(1-y_hat(a,:)).*(y-y_hat(a,:));
    e=b.*(1-b).*(w*g')';
    
    for i=1:n
        for j=1:q
            v(i,j)=v(i,j)+k*e(j)*x(i);   %输入层->隐层的权值更新
        end
    end
    r=r-k*e;         %隐层的阀值更新
    
    for i=1:q
        for j=1:L
            w(i,j)=w(i,j)+k*g(j)*b(i);   %隐层->输出层的权值更新
        end
    end
    h=h-k*g;
    
    if a>=m
        a=a-m;
    end
    a=a+1;
    iter=iter+1;
end

disp('输入层到隐层的权值为');v
disp('隐层的阀值为');r
disp('隐层到输出层的权值为');w
disp('输出层的阀值为');h

function y=fc_sigmod(x)
y=1./(1+exp(-x));
end
end
